package postgres

import (
  "context"
  "fmt"
  "go.uber.org/zap"
  "gorm.io/gorm"
  logger "simcard/collector/logger"
  "simcard/config"
  "simcard/errors"
  "simcard/model"
  "simcard/model/entity"
  "simcard/utils"
  "strings"
)

var SimCard = &simCard{}

type simCard struct{}

func init() {
  Register(SimCard)
}

func (a *simCard) Init() {
  if config.Conf.AutoMigrate {
    p := &entity.SimCard{}
    if db.Migrator().HasTable(p) {
      logger.Debug("table already exist: ", zap.String("table", p.TableName()))
      return
    }
    if err := db.AutoMigrate(p); err != nil {
      logger.Error("filed to create table please check config or manually create", zap.String("table", p.TableName()), zap.String("err", err.Error()))
    } else {
      logger.Info("create table successfully", zap.String("table", p.TableName()))
    }
  }
}

// Create
func (a *simCard) Create(ctx context.Context, m *entity.SimCard) (int64, error) {
  err := GetDB(ctx).Create(m).Error
  return m.Id, err
}

// CreateInBatch
func (a *simCard) CreateInBatch(ctx context.Context, m []*entity.SimCard, size int) error {
  err := GetDB(ctx).CreateInBatches(m, size).Error
  return err
}

// Find detail
func (a *simCard) Find(ctx context.Context, in *model.SimCardInfoRequest) (*entity.SimCard, error) {
  e := &entity.SimCard{}

  q := GetDB(ctx).Model(&entity.SimCard{})

  if in.Id == 0 {
    return e, errors.New("condition illegal")
  }
  err := q.First(&e, in.Id).Error
  return e, err
}

// Update
func (a *simCard) Update(ctx context.Context, id int64, dict map[string]interface{}) error {
  return GetDB(ctx).Model(&entity.SimCard{}).Where("id = ?", id).Updates(dict).Error
}

// UpdateByCondition
func (a *simCard) UpdateByCondition(ctx context.Context, req *model.UpdateSimCardByConditionRequest, dict map[string]interface{}) error {

  q := GetDB(ctx).Model(&entity.SimCard{})
  if req.Id != nil {
    q = q.Where("id = ?", req.Id)
  }

  if len(req.Ids) > 0 {
    q = q.Where("id IN (?)", req.Ids)
  }

  if req.EbikeId != nil {
    q = q.Where("ebike_id = ?", req.EbikeId)
  }

  if len(req.EbikeIds) > 0 {
    q = q.Where("ebike_id IN (?)", req.EbikeIds)
  }

  return q.Updates(dict).Error
}

// Delete
func (a *simCard) Delete(ctx context.Context, in *model.SimCardDeleteRequest) error {
  //if
  q := GetDB(ctx)

  if in.Id != nil {
    q = q.Where("id = ?", in.Id)
  }

  if len(in.Ids) > 0 {

    q = q.Where("id IN ?", in.Ids)

  }

  if in.EbikeId != nil {

    q = q.Where("ebike_id = ?", in.EbikeId)

  }

  if len(in.EbikeIds) > 0 {

    q = q.Where("ebike_id IN ?", in.EbikeIds)

  }

  return q.Delete(&entity.SimCard{}).Error
}

// List query list
func (a *simCard) List(ctx context.Context, in *model.SimCardListRequest, opts ...model.QueryOptions) (int, []*entity.SimCard, error) {

  var (
    opt      = model.GetQueryOption(opts...)
    q        = GetDB(ctx).Model(&entity.SimCard{})
    err      error
    total    int64
    simCards []*entity.SimCard
  )

  if in.Id != nil {

    q = q.Where("id = ?", in.Id)

  }

  if len(in.Ids) > 0 {

    q = q.Where("id IN ?", in.Ids)

  }

  if in.EbikeId != nil {

    q = q.Where("ebike_id = ?", in.EbikeId)

  }

  if len(in.EbikeIds) > 0 {

    q = q.Where("ebike_id IN ?", in.EbikeIds)

  }

  if in.UserId != nil {

    q = q.Where("user_id = ?", in.UserId)

  }

  if in.UserPhone != nil {

    q = q.Where("user_phone like ?", utils.SqlLike(in.UserPhone))

  }

  if in.Iccid != nil {

    q = q.Where("iccid like ?", utils.SqlLike(in.Iccid))

  }

  if in.AgentId != nil {

    q = q.Where("agent_id = ?", in.AgentId)

  }

  if in.Sn != nil {

    q = q.Where("sn like ?", utils.SqlLike(in.Sn))

  }

  if in.FrameCode != nil {

    q = q.Where("frame_code like ?", utils.SqlLike(in.FrameCode))

  }

  if in.EffectiveDate != nil {

    q = q.Where("effective_date = ?", in.EffectiveDate)

  }

  if in.ExpiredDate != nil {

    q = q.Where("expired_date = ?", in.ExpiredDate)

  }

  if in.Status != nil {

    q = q.Where("status = ?", in.Status)

  }

  if in.Detail != nil {

    q = q.Where("detail = ?", in.Detail)

  }

  if in.CreatedAt != nil {

    q = q.Where("created_at = ?", in.CreatedAt)

  }

  if in.UpdatedAt != nil {

    q = q.Where("updated_at = ?", in.UpdatedAt)

  }

  if len(opt.Conditions) > 0 {
    q = q.Where(strings.Join(opt.Conditions, " AND "))
  }

  if len(opt.SelectFields) > 0 {
    q = q.Select(opt.SelectFields)
  }

  if len(opt.OrderFields) > 0 {
    q = q.Order(fmt.Sprintf("%v", model.ParseOrder(opt.OrderFields)))
  }

  b := !opt.OnlyCount && !opt.OnlyList
  if opt.OnlyCount || b {
    if err = q.Count(&total).Error; err != nil {
      return 0, nil, err
    }
  }

  if opt.OnlyList || b {
    if err = q.Limit(in.Size).Offset((in.Index - 1) * in.Size).Find(&simCards).Error; err != nil {
      return 0, nil, err
    }
  }
  return int(total), simCards, nil
}

// ExecTransaction execute database transaction
func (a *simCard) ExecTransaction(ctx context.Context, callback func(ctx context.Context) error) error {
  return GetDB(ctx).Transaction(func(tx *gorm.DB) error {
    ctx = context.WithValue(ctx, ContextTxKey, tx)
    return callback(ctx)
  })
}
